@@ -6,6 +6,7 @@ from pay.models import OrderInfo  | 
            ||
| 6 | 6 | 
                 | 
            
| 7 | 7 | 
                 | 
            
| 8 | 8 | 
                class OrderInfoAdmin(admin.ModelAdmin):  | 
            
| 9 | 
                +    readonly_fields = ('order_id', 'prepay_id', 'transaction_id', 'unifiedorder_result', 'notify_msg')
               | 
            |
| 9 | 10 | 
                     list_display = ('order_id', 'photo_type', 'photo_status', 'from_uid', 'to_uid', 'pay_status', 'paid_at', 'reback_status', 'reback_at', 'status', 'created_at', 'updated_at')
               | 
            
| 10 | 11 | 
                     list_filter = ('photo_type', 'photo_status', 'pay_status', 'reback_status', 'status')
               | 
            
| 11 | 12 | 
                 | 
            
                @@ -0,0 +1,30 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +# Generated by Django 1.11.3 on 2017-07-13 23:59  | 
            |
| 3 | 
                +from __future__ import unicode_literals  | 
            |
| 4 | 
                +  | 
            |
| 5 | 
                +from django.db import migrations, models  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +  | 
            |
| 8 | 
                +class Migration(migrations.Migration):  | 
            |
| 9 | 
                +  | 
            |
| 10 | 
                + dependencies = [  | 
            |
| 11 | 
                +        ('pay', '0007_orderinfo_unifiedorder_result'),
               | 
            |
| 12 | 
                + ]  | 
            |
| 13 | 
                +  | 
            |
| 14 | 
                + operations = [  | 
            |
| 15 | 
                + migrations.AddField(  | 
            |
| 16 | 
                + model_name='orderinfo',  | 
            |
| 17 | 
                + name='notify_msg',  | 
            |
| 18 | 
                + field=models.TextField(blank=True, help_text='\u56de\u8c03\u4fe1\u606f', null=True, verbose_name='notify_msg'),  | 
            |
| 19 | 
                + ),  | 
            |
| 20 | 
                + migrations.AddField(  | 
            |
| 21 | 
                + model_name='orderinfo',  | 
            |
| 22 | 
                + name='prepay_id',  | 
            |
| 23 | 
                + field=models.CharField(blank=True, help_text='\u9884\u652f\u4ed8\u4ea4\u6613\u4f1a\u8bdd\u6807\u8bc6', max_length=255, null=True, verbose_name='prepay_id'),  | 
            |
| 24 | 
                + ),  | 
            |
| 25 | 
                + migrations.AddField(  | 
            |
| 26 | 
                + model_name='orderinfo',  | 
            |
| 27 | 
                + name='transaction_id',  | 
            |
| 28 | 
                + field=models.CharField(blank=True, help_text='\u5fae\u4fe1\u8ba2\u5355\u53f7', max_length=255, null=True, verbose_name='transaction_id'),  | 
            |
| 29 | 
                + ),  | 
            |
| 30 | 
                + ]  | 
            
                @@ -53,6 +53,9 @@ class OrderInfo(CreateUpdateMixin):  | 
            ||
| 53 | 53 | 
                 | 
            
| 54 | 54 | 
                order_id = ShortUUIDField(_(u'order_id'), max_length=255, help_text=u'订单唯一标识', db_index=True)  | 
            
| 55 | 55 | 
                 | 
            
| 56 | 
                +    prepay_id = models.CharField(_('prepay_id'), max_length=255, blank=True, null=True, help_text=u'预支付交易会话标识')
               | 
            |
| 57 | 
                +    transaction_id = models.CharField(_('transaction_id'), max_length=255, blank=True, null=True, help_text=u'微信订单号')
               | 
            |
| 58 | 
                +  | 
            |
| 56 | 59 | 
                group_id = models.CharField(_(u'group_id'), max_length=255, blank=True, null=True, help_text=u'群组唯一标识', db_index=True)  | 
            
| 57 | 60 | 
                session_id = models.CharField(_(u'session_id'), max_length=255, blank=True, null=True, help_text=u'照片组唯一标识,同 PhotosInfo 表', db_index=True)  | 
            
| 58 | 61 | 
                photo_id = models.CharField(_(u'photo_id'), max_length=255, blank=True, null=True, help_text=u'飞图唯一标识', db_index=True)  | 
            
                @@ -75,7 +78,10 @@ class OrderInfo(CreateUpdateMixin):  | 
            ||
| 75 | 78 | 
                reback_status = models.BooleanField(_(u'reback_status'), default=False, help_text=u'退款状态', db_index=True)  | 
            
| 76 | 79 | 
                reback_at = models.DateTimeField(_(u'reback_at'), blank=True, null=True, help_text=_(u'退款时间'))  | 
            
| 77 | 80 | 
                 | 
            
| 81 | 
                + # 微信统一下单  | 
            |
| 78 | 82 | 
                unifiedorder_result = models.TextField(_(u'unifiedorder_result'), blank=True, null=True, help_text=_(u'统一下单结果'))  | 
            
| 83 | 
                + # 微信支付回调  | 
            |
| 84 | 
                +    notify_msg = models.TextField(_('notify_msg'), blank=True, null=True, help_text=u'回调信息')
               | 
            |
| 79 | 85 | 
                 | 
            
| 80 | 86 | 
                class Meta:  | 
            
| 81 | 87 | 
                         verbose_name = _('orderinfo')
               | 
            
                @@ -1,6 +1,5 @@  | 
            ||
| 1 | 1 | 
                # -*- coding: utf-8 -*-  | 
            
| 2 | 2 | 
                 | 
            
| 3 | 
                -import xmltodict  | 
            |
| 4 | 3 | 
                from django.conf import settings  | 
            
| 5 | 4 | 
                from django.db import transaction  | 
            
| 6 | 5 | 
                from django.shortcuts import HttpResponse  | 
            
                @@ -9,6 +8,8 @@ from paginator import pagination  | 
            ||
| 9 | 8 | 
                from pywe_exception import WeChatPayException  | 
            
| 10 | 9 | 
                from pywe_pay import WeChatPay  | 
            
| 11 | 10 | 
                from pywe_response import WXPAY_NOTIFY_FAIL, WXPAY_NOTIFY_SUCCESS  | 
            
| 11 | 
                +from pywe_sign import check_signature  | 
            |
| 12 | 
                +from pywe_xml import xml_to_dict  | 
            |
| 12 | 13 | 
                from TimeConvert import TimeConvert as tc  | 
            
| 13 | 14 | 
                 | 
            
| 14 | 15 | 
                from account.models import UserIncomeExpensesInfo, UserInfo  | 
            
                @@ -100,6 +101,9 @@ def wx_order_create_api(request):  | 
            ||
| 100 | 101 | 
                return response(OrderStatusCode.WX_UNIFIED_ORDER_FAIL)  | 
            
| 101 | 102 | 
                 | 
            
| 102 | 103 | 
                     prepay_id = prepay_data.get('prepay_id', '')
               | 
            
| 104 | 
                + order.prepay_id = prepay_id  | 
            |
| 105 | 
                + order.save()  | 
            |
| 106 | 
                +  | 
            |
| 103 | 107 | 
                if trade_type == 'JSAPI' or trade_type == 'MINIAPP':  | 
            
| 104 | 108 | 
                wxpay_params = wxpay.jsapi.get_jsapi_params(prepay_id)  | 
            
| 105 | 109 | 
                elif trade_type == 'APP':  | 
            
                @@ -204,7 +208,7 @@ def wx_order_query_api(request):  | 
            ||
| 204 | 208 | 
                # 订单查询  | 
            
| 205 | 209 | 
                query_data = wxpay.order.query(transaction_id, order_id)  | 
            
| 206 | 210 | 
                # 签名校验  | 
            
| 207 | 
                - if not wxpay.check_signature(query_data):  | 
            |
| 211 | 
                + if not check_signature(query_data):  | 
            |
| 208 | 212 | 
                return response(OrderStatusCode.SIGN_CHECK_FAIL)  | 
            
| 209 | 213 | 
                 | 
            
| 210 | 214 | 
                # 交易状态  | 
            
                @@ -262,36 +266,36 @@ def wx_order_detail_api(request):  | 
            ||
| 262 | 266 | 
                @transaction.atomic  | 
            
| 263 | 267 | 
                def wx_notify_url_api(request):  | 
            
| 264 | 268 | 
                """ 支付异步通知回调地址 """  | 
            
| 265 | 
                - try:  | 
            |
| 266 | 
                - data = xmltodict.parse(request.body)['xml']  | 
            |
| 267 | 
                - except xmltodict.ParsingInterrupted:  | 
            |
| 268 | 
                - # 解析 XML 失败  | 
            |
| 269 | 
                + data = xml_to_dict(request.body)  | 
            |
| 270 | 
                + if isinstance(data, basestring):  | 
            |
| 269 | 271 | 
                return HttpResponse(WXPAY_NOTIFY_FAIL)  | 
            
| 270 | 272 | 
                 | 
            
| 271 | 273 | 
                     trade_type = data.get('trade_type', '')
               | 
            
| 272 | 274 | 
                 | 
            
| 273 | 
                - # 根据 trade_type 获取 wechat 配置  | 
            |
| 274 | 
                -    wechat = WECHAT.get(trade_type, {})
               | 
            |
| 275 | 
                - # WeChatPay 初始化  | 
            |
| 276 | 
                -    wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID'))
               | 
            |
| 277 | 
                -  | 
            |
| 278 | 275 | 
                # 签名校验  | 
            
| 279 | 
                - if not wxpay.check_signature(data):  | 
            |
| 280 | 
                - return response(OrderStatusCode.SIGN_CHECK_FAIL)  | 
            |
| 276 | 
                +    if not check_signature(data, settings.WECHAT.get(trade_type, {}).get('apiKey')):
               | 
            |
| 277 | 
                + return HttpResponse(WXPAY_NOTIFY_FAIL)  | 
            |
| 281 | 278 | 
                 | 
            
| 282 | 
                -    out_trade_no = data.get('out_trade_no', '')
               | 
            |
| 279 | 
                + # 通信标识  | 
            |
| 283 | 280 | 
                     return_code = data.get('return_code', '')
               | 
            
| 284 | 
                -    result_code = data.get('result_code', '')
               | 
            |
| 285 | 
                -  | 
            |
| 286 | 
                - if return_code != 'SUCCESS' or result_code != 'SUCCESS':  | 
            |
| 281 | 
                + if return_code != 'SUCCESS':  | 
            |
| 287 | 282 | 
                return HttpResponse(WXPAY_NOTIFY_FAIL)  | 
            
| 288 | 283 | 
                 | 
            
| 284 | 
                +    out_trade_no = data.get('out_trade_no', '')
               | 
            |
| 289 | 285 | 
                try:  | 
            
| 290 | 286 | 
                order = OrderInfo.objects.get(order_id=out_trade_no)  | 
            
| 291 | 287 | 
                except OrderInfo.DoesNotExist:  | 
            
| 292 | 288 | 
                return response(OrderStatusCode.WX_ORDER_NOT_FOUND)  | 
            
| 293 | 289 | 
                 | 
            
| 294 | 
                - order_paid_success(order)  | 
            |
| 290 | 
                + order.notify_msg = request.body  | 
            |
| 291 | 
                +    order.transaction_id = data.get('transaction_id', '')
               | 
            |
| 292 | 
                + order.save()  | 
            |
| 293 | 
                +  | 
            |
| 294 | 
                +    result_code = data.get('result_code', '')
               | 
            |
| 295 | 
                + if result_code == 'SUCCESS':  | 
            |
| 296 | 
                + order_paid_success(order)  | 
            |
| 297 | 
                + else:  | 
            |
| 298 | 
                + order_paid_fail(order)  | 
            |
| 295 | 299 | 
                 | 
            
| 296 | 300 | 
                return HttpResponse(WXPAY_NOTIFY_SUCCESS)  | 
            
| 297 | 301 | 
                 | 
            
                @@ -31,6 +31,8 @@ pywe-miniapp==1.0.0  | 
            ||
| 31 | 31 | 
                pywe-oauth==1.0.3  | 
            
| 32 | 32 | 
                pywe-pay==1.0.5  | 
            
| 33 | 33 | 
                pywe-response==1.0.1  | 
            
| 34 | 
                +pywe-sign==1.0.5  | 
            |
| 35 | 
                +pywe-xml==1.0.0  | 
            |
| 34 | 36 | 
                qiniu==7.1.4  | 
            
| 35 | 37 | 
                redis-extensions==1.0.50  | 
            
| 36 | 38 | 
                requests==2.18.1  |